package com.wo.cloud.elasticsearch.util;

import com.alibaba.fastjson.JSON;
import com.wo.cloud.core.entity.Response;
import org.apache.http.HttpHost;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author liry
 * @version 1.0
 * @date Created on 2021/3/25 18:10
 * Description: es 工具类
 */
public class EsUtil<T> {

    @Resource
    public RestHighLevelClient restHighLevelClient;

    // 创建索引， 保存数据
    public Response indexData(String indices, String index,
                              String id, T source) throws IOException {
        IndexRequest indexRequest = new IndexRequest(indices, index, id);

        String jsonString = JSON.toJSONString(source);
        indexRequest.source(jsonString, XContentType.JSON);


        IndexResponse response = restHighLevelClient.index(indexRequest);

        return Response.data(response);
    }

    // 检索数据
    public Response getData(String indices, String index,
                            String id, Class<T> tClass) throws IOException {
        GetRequest getRequest = new GetRequest(
                indices,
                index,
                id);

        GetResponse response = restHighLevelClient.get(getRequest);

        // 获取source并转成string类型
        String sourceAsString = response.getSourceAsString();

        // 解析成JavaBean
        T object = JSON.parseObject(sourceAsString, tClass);


        return Response.data(object);
    }

    // 查询所有数据
    public Response queryAllData(String indices, String index,
                                 int from, int size,
                                 Class<T> tClass) throws IOException {
        // 指定化索引
        SearchRequest searchRequest = new SearchRequest(indices);
        // 指定类型
        searchRequest.types(index);

        SearchSourceBuilder searchRequestBuilder = new SearchSourceBuilder();

        // 查询所有
        searchRequestBuilder.query(QueryBuilders.matchAllQuery());

        // 设置分页
        searchRequestBuilder.from(from);
        searchRequestBuilder.size(size);

        // 包装请求信息
        searchRequest.source(searchRequestBuilder);

        // 发送请求
        SearchResponse search = restHighLevelClient.search(searchRequest);

        SearchHits hits = search.getHits();

        return getHitsData(hits, tClass);
    }


    // 时间范围搜索
    public Response rangeData(String indices, String index,
                              String fromDate, String toDate,
                              int from, int size,
                              Class<T> tClass) throws IOException {
        // 指定化索引
        SearchRequest searchRequest = new SearchRequest(indices);

        // 指定类型
        searchRequest.types(index);

        SearchSourceBuilder searchRequestBuilder = new SearchSourceBuilder();

        // 范围查询
        // 问题： elasticsearch 在处理 范围查询时，对text类型数据不生效，查询结果的数据不在该范围内
        // 对Date类型数据查询，结果正常
        //  grok 对原始数据分词之后都是text类型，因此在对text类型数据进行范围查询时，需要在被查询字段上添加.keyword
        RangeQueryBuilder rangeQueryBuilder = QueryBuilders
                .rangeQuery("logTimestamp.keyword")
                .from(fromDate)
                .to(toDate)
                .format("epoch_millis");
        searchRequestBuilder.query(rangeQueryBuilder);

        // 设置分页
        searchRequestBuilder.from(from);
        searchRequestBuilder.size(size);

        // 包装请求信息
        searchRequest.source(searchRequestBuilder);

        // 发送请求
        SearchResponse search = restHighLevelClient.search(searchRequest);

        SearchHits hits = search.getHits();
        return getHitsData(hits, tClass);
    }

    // 词条查询
    public Response searchData(String indices, String index,
                               String fieldName, String text,
                               int from, int size,
                               Class<T> tClass) throws IOException {
        // 指定化索引
        SearchRequest searchRequest = new SearchRequest(indices);
        // 指定类型
        searchRequest.types(index);

        SearchSourceBuilder searchRequestBuilder = new SearchSourceBuilder();

        // 根据条件查询： loglevel = INFO
        searchRequestBuilder.query(QueryBuilders.matchQuery(fieldName, text));

        // 设置分页
        searchRequestBuilder.from(from);
        searchRequestBuilder.size(size);

        // 包装请求信息
        searchRequest.source(searchRequestBuilder);

        // 发送请求
        SearchResponse search = restHighLevelClient.search(searchRequest);

        System.out.println(search);

        SearchHits hits = search.getHits();

        return getHitsData(hits, tClass);
    }


    // 获取查询到的数据
    private Response getHitsData(SearchHits hits, Class<T> tClass) {
        List<T> result = new ArrayList<>();
        hits.forEach(hit -> {

            // 将map 转换为string
            String sourceAsString = hit.getSourceAsString();
            T logVo = JSON.parseObject(sourceAsString, tClass);
            result.add(logVo);

            // 获取 source 的Map结构
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();
            // 获取 message 的值
            System.out.println("--message--: " + sourceAsMap.get("message"));
        });
        return Response.data(result);
    }
}
